/*
 * Copyright (C) 2010 Graham Allan
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package edu.strath.cis.grallan.findbugs.adaptiveranking.analysis;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;

import org.apache.commons.math.stat.descriptive.moment.Mean;
import org.apache.commons.math.stat.descriptive.moment.StandardDeviation;

/**
 * @author Graham Allan (grallan@cis.strath.ac.uk)
 */
public class OutlierDetectionAnalysis {

	private final String baseDir;

	public static void main(String[] args) throws FileNotFoundException, IOException {
		new OutlierDetectionAnalysis(
			"/home/graham/uni/FinalYearProject/fb-projects/analyses/fll-sw/").writeOutliers();
		new OutlierDetectionAnalysis(
			"/home/graham/uni/FinalYearProject/fb-projects/analyses/intellij/").writeOutliers();
		new OutlierDetectionAnalysis(
			"/home/graham/uni/FinalYearProject/fb-projects/analyses/lucene/").writeOutliers();
		new OutlierDetectionAnalysis(
			"/home/graham/uni/FinalYearProject/fb-projects/analyses/jython/").writeOutliers();
		new OutlierDetectionAnalysis(
			"/home/graham/uni/FinalYearProject/evaluation/ciboodle/analysis/").writeOutliers();
	}
	
	public OutlierDetectionAnalysis(String baseDir) {
		this.baseDir = baseDir;
	}
	
	public void writeOutliers() throws IOException {
		System.out.println("Writing outliers in directory: " + baseDir);
		FileWriter writer = new FileWriter(baseDir + "outliers.txt");
		
		try {
			findOutliers(baseDir, "alertMap-ALERT_TYPE.properties", writer);
			findOutliers(baseDir, "alertMap-PACKAGE.properties", writer);
			findOutliers(baseDir, "alertMap-CLASS.properties", writer);
			findOutliers(baseDir, "alertMap-METHOD.properties", writer);	
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		writer.close();
	}

	private void findOutliers(String directory, String propertyFile, FileWriter writer) throws IOException, FileNotFoundException {
		final Properties properties = new Properties();
		properties.load(new FileReader(directory + propertyFile));

		int numPopulations = properties.size();
		double[] values = new double[numPopulations];

		int i = 0;
		for (Object o : properties.values()) {
			String str = (String) o;

			try {
				Double size = Double.parseDouble(str);
				values[i] = size.doubleValue();
				i++;
			} catch (NumberFormatException e) {
				e.printStackTrace();
			}
		}

		StandardDeviation stdDev = new StandardDeviation();
		double stdDevResult = stdDev.evaluate(values);

		Mean mean = new Mean();
		double meanAverage = mean.evaluate(values);

		List<String> outliers = new ArrayList<String>();

		double threeStdDevs = 3 * stdDevResult;

		Enumeration<Object> keys = properties.keys();
		while (keys.hasMoreElements()) {
			String key = (String) keys.nextElement();

			Double size = Double.parseDouble((String) properties.get(key));
			double xMinusMu = size - meanAverage;
			if (Math.abs(xMinusMu) > threeStdDevs) {
				outliers.add(key);
			}
		}
		

		Collections.sort(outliers, new Comparator<String>() {
			public int compare(String o1, String o2) {
				Double size1 = Double.parseDouble((String) properties.get(o1));
				Double size2 = Double.parseDouble((String) properties.get(o2));

				return Double.compare(size2.doubleValue(), size1.doubleValue()); // descending
			}
		});

		writer.append(propertyFile + "\n");
		writer.append(String.format("Mean=%f, 3StdDevs=%f%n", meanAverage, threeStdDevs));

		for (String outlier : outliers) {
			Double size = Double.parseDouble((String) properties.get(outlier));
			writer.append(String.format("\t%4d: %s%n", size.intValue(), outlier));
		}
		
	}

}
